package cn.smbms.controller;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;

import cn.smbms.config.AlipayConfig;
import cn.smbms.pojo.AlipayUser;
import cn.smbms.service.AlipayService;

//@Controller
@RequestMapping("/api")
public class AlipayController {

	@Autowired
	private AlipayConfig alipayConfig;
	
	@Autowired
	private AlipayService alipayService;

	String redirect_uri = "http://localhost:8088/smbms2/api/returnurl";

	// http://localhost:8088/smbms2/api/oauth2app
	@RequestMapping("oauth2app")
	public String oauth2app() {
		String url = "https://openauth.alipaydev.com/oauth2/appToAppAuth.htm?app_id=" + alipayConfig.getAppID()
				+ "&redirect_uri=" + redirect_uri;
		return "redirect:" + url;
	}

	// http://localhost:8088/smbms2/api/oauth2auth
	@RequestMapping("oauth2auth")
	public String oauth2auth() {
		String url = "https://openauth.alipaydev.com/oauth2/publicAppAuthorize.htm?app_id=" + alipayConfig.getAppID()
				+ "&scope=auth_user&redirect_uri=" + redirect_uri;
		return "redirect:" + url;
	}

	/**
	 * 
	 * @param app_id
	 * @param app_auth_code 第三方授权code
	 * @param response
	 * @param request
	 * @return
	 * @throws IOException
	 * @throws AlipayApiException
	 */
	@RequestMapping("returnurl")
	public void returnurl(String app_id, String auth_code, String app_auth_code, HttpServletResponse response, HttpServletRequest request)
			throws IOException, AlipayApiException {
		//访问令牌
		PrintWriter out = response.getWriter();		
		if(auth_code!=null && !"".equals(auth_code)) {
			out.println("访问令牌 auth_code=" + auth_code);
			//
			String token = alipayService.getAccessToken(auth_code);
			out.println("token=" + token);
			// 查询用户信息
			AlipayUser user = alipayService.getUserInfo(token);
			out.println("user=" + user);
		}
		//应用授权
		else if(app_auth_code!=null && !"".equals(app_auth_code)) {
			out.println("应用授权 app_auth_code=" + app_auth_code);
			//
			String token = alipayService.getAppAuthToken(app_auth_code);
			out.println("token=" + token);
			// 查询授权信息
			String userId = alipayService.getAuthInfo(token);
			out.println("userId=" + userId);
		} else {
			out.println("授权码出错：auth_code=[" + auth_code + "] 或 app_auth_code=[" + app_auth_code + "]");
		}
	}

	/**
	 * 请求支付宝支付 
	 * http://localhost:8088/smbms2/api/pay?trade_no=2&total_amount=1&subject=测试订单
	 * 
	 * @param trade_no     商户订单号，商户网站订单系统中唯一订单号，必填
	 * @param total_amount 付款金额，必填
	 * @param subject      订单名称，必填
	 * @throws IOException
	 * 
	 */
	@RequestMapping(value = "/pay")
	public void pay(String trade_no, String total_amount, String subject, HttpServletResponse response)
			throws IOException {
		// 获得初始化的AlipayClient
		AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig.getUrl(), alipayConfig.getAppID(),
				alipayConfig.getRsaPrivateKey(), alipayConfig.getFormat(), alipayConfig.getCharset(),
				alipayConfig.getAlipayPublicKey(), alipayConfig.getSignType());
		// 设置请求参数
		AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
		alipayRequest.setReturnUrl(alipayConfig.getReturnUrl());
		alipayRequest.setNotifyUrl(alipayConfig.getNotifyUrl());
		try {
			alipayRequest.setBizContent("{\"out_trade_no\":\"" + trade_no + "\"," + "\"total_amount\":\"" + total_amount
					+ "\"," + "\"subject\":\"" + subject + "\"," + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");

			// 若想给BizContent增加其他可选请求参数，以增加自定义超时时间参数timeout_express来举例说明
			// alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
			// + "\"total_amount\":\""+ total_amount +"\","
			// + "\"subject\":\""+ subject +"\","
			// + "\"body\":\""+ body +"\","
			// + "\"timeout_express\":\"10m\","
			// + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
			// 请求参数可查阅【电脑网站支付的API文档-alipay.trade.page.pay-请求参数】章节

			String form = "";
			try {
				form = alipayClient.pageExecute(alipayRequest).getBody(); // 调用SDK生成表单
			} catch (AlipayApiException e) {
				e.printStackTrace();
			}
			response.setContentType("text/html;charset=" + alipayConfig.getCharset());
			response.getWriter().write(form);// 直接将完整的表单html输出到页面
			response.getWriter().flush();
			response.getWriter().close();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 异步跟踪支付状态
	 * 
	 * @param trade_no     商户订单号
	 * @param total_amount 付款金额
	 * @param alipay_no    支付宝交易号
	 * @param response
	 * @param request
	 */
	@RequestMapping(value = "/notify", method = RequestMethod.POST)
	public void notifyStatus(String trade_no, String total_amount, @RequestParam("trade_no") String alipay_no,
			String trade_status, HttpServletResponse response, HttpServletRequest request) throws Exception {
		// 获取支付宝POST过来反馈信息
		Map<String, String> params = new HashMap<String, String>();
		request.setCharacterEncoding("UTF-8");
		Map<String, String[]> requestParams = request.getParameterMap();
		for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
			String name = (String) iter.next();
			String[] values = (String[]) requestParams.get(name);
			String valueStr = "";
			for (int i = 0; i < values.length; i++) {
				valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
			}
			params.put(name, valueStr);
		}
		// 调用SDK验证签名
		boolean signVerified = false;
		signVerified = AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipayPublicKey(), alipayConfig.getCharset(),
				alipayConfig.getSignType());
		// ——请在这里编写您的程序（以下代码仅作参考）——
		/*
		 * 实际验证过程建议商户务必添加以下校验： 1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
		 * 2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额）， 3、校验通知中的seller_id（或者seller_email)
		 * 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email）
		 * 4、验证app_id是否为该商户本身。
		 */
		if (signVerified) {// 验证成功
			if (trade_status.equals("TRADE_FINISHED")) {
				// 判断该笔订单是否在商户网站中已经做过处理
				// 如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
				// 如果有做过处理，不执行商户的业务程序

				// 注意：
				// 退款日期超过可退款期限后（如三个月可退款），支付宝系统发送该交易状态通知
			} else if (trade_status.equals("TRADE_SUCCESS")) {
				// 判断该笔订单是否在商户网站中已经做过处理
				// 如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
				// 如果有做过处理，不执行商户的业务程序

				// 注意：
				// 付款完成后，支付宝系统发送该交易状态通知
			}
			response.getWriter().println("success");// 请不要修改或删除

		} else {// 验证失败
			response.getWriter().println("fail");
		}
	}

	/**
	 * 同步通知商户支付宝支付状态
	 * 
	 * @param response
	 * @param request
	 * @throws Exception
	 */
	@RequestMapping(value = "/return", method = RequestMethod.GET)
	public void callback(String trade_no, String total_amount, @RequestParam("trade_no") String alipay_no,
			String trade_status, HttpServletResponse response, HttpServletRequest request) throws Exception {
		// 获取支付宝GET过来反馈信息
		Map<String, String> params = new HashMap<String, String>();
		Map<String, String[]> requestParams = request.getParameterMap();
		for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
			String name = (String) iter.next();
			String[] values = (String[]) requestParams.get(name);
			String valueStr = "";
			for (int i = 0; i < values.length; i++) {
				valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
			}
			// 乱码解决，这段代码在出现乱码时使用
			valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
			params.put(name, valueStr);
		}
		//
		boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipayPublicKey(),
				alipayConfig.getCharset(), alipayConfig.getSignType()); // 调用SDK验证签名

		// ——请在这里编写您的程序（以下代码仅作参考）——
		if (signVerified) {
			response.sendRedirect(String.format(alipayConfig.getPaymentSuccessUrl(), trade_no));
		} else {
			response.sendRedirect(String.format(alipayConfig.getPaymentFailureUrl()));
		}
	}
	
	@RequestMapping("success")
	@ResponseBody
	public String success(String orderNo) {
		return "订单【"+orderNo+"】支付成功";
	}
	
	@RequestMapping("fail")
	@ResponseBody
	public String fail(String orderNo) {
		return "订单【"+orderNo+"】支付失败";
	}
}
